#include<iostream>
#include<vector>
#include<semaphore.h>
#include<pthread.h>
#include<unistd.h>
#include<functional>

using namespace std;

//循环队列
template<class T>
class RingQueue
{
public:
    RingQueue(int CountOfSpace)
        : _StepOfProducter(0)
        ,_StepOfConsumer(0)
    {
        _rq.resize(CountOfSpace);
        sem_init(&_CountOfData,0,0);
        sem_init(&_CountOfSpace,0,CountOfSpace);
        pthread_mutex_init(&_producter,NULL);
        pthread_mutex_init(&_consumer,NULL);
    }

    ~RingQueue()
    {
        sem_destroy(&_CountOfData);
        sem_destroy(&_CountOfSpace);
        pthread_mutex_destroy(&_producter);
        pthread_mutex_destroy(&_consumer);
    }

    void Push(T& data)
    {
        sem_wait(&_CountOfSpace);
        pthread_mutex_lock(&_producter);
        _rq[_StepOfProducter]=data;
        _StepOfProducter=(_StepOfProducter+1)%_rq.size();
        pthread_mutex_unlock(&_producter);
        sem_post(&_CountOfData);
    }

    void Pop(T& data)
    {
        sem_wait(&_CountOfData);
        pthread_mutex_lock(&_consumer);
        data=_rq[_StepOfConsumer];
        _StepOfConsumer=(_StepOfConsumer+1)%_rq.size();
        pthread_mutex_unlock(&_consumer);
        sem_post(&_CountOfSpace);
    }

private:
    vector<T> _rq;
    sem_t _CountOfSpace;
    sem_t _CountOfData;
    pthread_mutex_t _producter;
    pthread_mutex_t _consumer;
    int _StepOfProducter;
    int _StepOfConsumer;
};

//封装线程
template<class T>
class Pthread
{
public:
    Pthread(function<void(T&)> func,T& data,string name)
        :_func(func)
        ,_data(data)
        ,_pthread_name(name)
    {}

    ~Pthread()
    {}

    static void* thread_fun(void* arg)
    {
        Pthread<T>* p=reinterpret_cast<Pthread<T>*>(arg);
        p->_func(p->_data);
        return nullptr;
    }

    void Start()
    {
        if(-1==pthread_create(&_pthread_id,NULL,thread_fun,this))
        {
            perror("pthread_create");
            return;
        }
    }

    void Wait()
    {
        pthread_join(_pthread_id,NULL);
    }

    void Detach()
    {
        pthread_detach(_pthread_id);
    }

    string GetPthreadName()
    {
        return _pthread_name;
    }
  
private:
    pthread_t _pthread_id;//线程ID
    string _pthread_name;//线程名
    T& _data;//临界资源
    function<void(T&)> _func;//线程执行的函数
};


void Product(RingQueue<int>& rq)
{
    while(true)
    {
        int data=rand()%100;
        rq.Push(data);
        cout<<"producter: "<<pthread_self()<<" product:"<<data<<endl;
        sleep(1);
    }
}

void Consume(RingQueue<int>& rq)
{
    while(true)
    {
        int data=0;
        rq.Pop(data);
        cout<<"consumer: "<<pthread_self()<<" consume:"<<data<<endl;
        sleep(1);
    }
}

void StartProduct(vector<Pthread<RingQueue<int>>>& pthreads,RingQueue<int>& rq,int num)
{
    while(num--)
    {
        pthreads.push_back(Pthread<RingQueue<int>>(Product,rq,"producter"+to_string(num)));
        pthreads.back().Start();
    }
}

void StartConsume(vector<Pthread<RingQueue<int>>>& pthreads,RingQueue<int>& rq,int num)
{
    while(num--)
    {
        pthreads.push_back(Pthread<RingQueue<int>>(Consume,rq,"consumer"+to_string(num)));
        pthreads.back().Start();
    }
}

void WaitAllPthreads(vector<Pthread<RingQueue<int>>>& pthreads)
{
    int i=1;
    for(auto& e:pthreads)
    {
        e.Wait();
    }
}

int main()
{
    srand(time(NULL));
    vector<Pthread<RingQueue<int>>> pthreads;
    RingQueue<int> rq(5);
    StartProduct(pthreads,rq,3);
    StartConsume(pthreads,rq,4);
    WaitAllPthreads(pthreads);
    return 0;
}